package com.alibaba.algo.apiimpl.user;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.algo.cooperation.feign.vo.res.ResourceActionResVO;
import com.alibaba.algo.cooperation.usercomponent.service.user.SysResourceService;
import com.alibaba.algo.cooperation.usercomponent.vo.req.user.ActionData;
import com.alibaba.algo.cooperation.usercomponent.vo.req.user.ResourceActionRequestVO;
import com.alibaba.algo.cooperation.usercomponent.vo.req.user.ResourceRequestVO;
import com.alibaba.algo.cooperation.usercomponent.vo.req.user.SelectResourceListRequestVO;
import com.alibaba.algo.cooperation.usercomponent.vo.req.xml.ImportParam;
import com.alibaba.algo.core.base.PagerEntity;
import com.alibaba.algo.domain.user.SysResourceDomain;
import com.alibaba.algo.entity.user.SysAction;
import com.alibaba.algo.entity.user.SysResource;
import com.alibaba.algo.entity.user.SysResourceAction;
import com.alibaba.algo.utils.XMLUtil;
import com.alibaba.algo.xml.*;
import lombok.extern.slf4j.Slf4j;
import com.alibaba.algo.cooperation.common.BaseResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.time.Instant;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * 类SysResourceServiceImpl.java的实现描述：资源 serviceimpl
 *
 * @author nieganggang 2021-03-12 16:08:17
 */
//不兼容现有资源模型，弃用
@Slf4j
@RestController
public class SysResourceServiceImpl implements SysResourceService {

    @Autowired
    SysResourceDomain sysResourceDomain;

    @Override
    public BaseResult<PagerEntity<SysResource>> selectPage(@RequestBody SelectResourceListRequestVO selectResourceListRequestVO) {
        PagerEntity<SysResource> pagerEntity = sysResourceDomain.selectResourcePage(selectResourceListRequestVO);
        return BaseResult.buildSuccess(pagerEntity);
    }

    @Override
    public BaseResult selectResourceAction(Long resourceId, String appCode) {
        List<ResourceActionResVO> resourceActionResVOS = sysResourceDomain.qryResourceActionByIdAndAppCode(resourceId, appCode);
        return BaseResult.buildSuccess(resourceActionResVOS);
    }

    @Override
    public BaseResult updateResourceAction(ResourceActionRequestVO param) {
        ActionData actionData = param.getActionData();
        if (ObjectUtils.isEmpty(param.getResourceId()) || ObjectUtils.isEmpty(actionData) || StringUtils.isEmpty(param.getAppCode())) {
            return BaseResult.buildError("入参格式出错");
        }
        return sysResourceDomain.updateResourceAction(param);
    }

    @Override
    public BaseResult removeResourceAction(ResourceActionRequestVO param) {
        sysResourceDomain.removeResourceAction(param);
        return BaseResult.buildSuccess("删除成功！");
    }

    @Override
    public BaseResult removeResource(ResourceRequestVO vo) {
        if (ObjectUtils.isEmpty(vo) && CollectionUtils.isEmpty(vo.getResourceIds())) {
            return BaseResult.buildError("入参有误！");
        }
        vo.getResourceIds().forEach(item -> {
            SysResource resource = sysResourceDomain.getById(item);
            if (!ObjectUtils.isEmpty(resource)) {
                //删除菜单
                sysResourceDomain.removeResource(resource.getId());
            }
        });
        return BaseResult.buildSuccess("删除成功！");
    }


    @Override
    public void resourceExport(HttpServletResponse response, ImportParam param) {
        if (ObjectUtils.isEmpty(param) || CollectionUtils.isEmpty(param.getResourceIds())) {
            throw new RuntimeException("请选择需要导出的菜单！");
        }
        //同步数据
        List<SysResource> resources = sysResourceDomain.qryResourcesByIds(param.getResourceIds());
        FileXML fileXML = new FileXML();
        List<ResourceXML> resourceXMLs = new ArrayList<>();
        List<ActionXML> actionXMLs = new ArrayList<>();
        resources.forEach(item -> {
            ResourceXML resourceXML = new ResourceXML();
            BeanUtil.copyProperties(item, resourceXML);
            List<SysResourceAction> resourceActions = sysResourceDomain.qryByResourceIdAndAppCode(item.getId(), item.getAppCode());
            if (!CollectionUtils.isEmpty(resourceActions)) {
                List<ResourceActionXML> resourceActionXMLs = new ArrayList<>();
                resourceActions.forEach(a -> {
                    ResourceActionXML resourceActionXML = new ResourceActionXML();
                    BeanUtil.copyProperties(a, resourceActionXML);
                    resourceActionXMLs.add(resourceActionXML);
                    SysAction action = sysResourceDomain.getActionById(a.getActionId());
                    ActionXML actionXML = new ActionXML();
                    BeanUtil.copyProperties(action, actionXML);
                    actionXMLs.add(actionXML);
                });
                resourceXML.setResourceActions(resourceActionXMLs);
            }
            resourceXMLs.add(resourceXML);
        });
        fileXML.setResources(resourceXMLs);
        fileXML.setActions(actionXMLs);
        String xml = XMLUtil.covertObjToXML(fileXML);
        ServletOutputStream outputStream;
        try {
            outputStream = response.getOutputStream();

            ByteArrayInputStream inputStream = new ByteArrayInputStream(xml.getBytes());
            String timestamp = String.valueOf(Instant.now().toEpochMilli());
            response.setContentType("application/xml");
            String disposition = "attachment; filename=" + timestamp + "_data.xml";
            response.setHeader("Content-Disposition", disposition);
            int len;
            byte[] bytes = new byte[1024];
            while ((len = inputStream.read(bytes)) != -1) {
                //读取输出流
                outputStream.write(bytes, 0, len);
            }
            outputStream.flush(); //刷新
            outputStream.close();
            inputStream.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public BaseResult resourceImport(@RequestBody MultipartFile file, String appCode) {
        if (ObjectUtils.isEmpty(file)) {
            return BaseResult.buildError("请选择导入的文件！");
        }
        String contentType = file.getContentType();
        assert contentType != null;
        if (!contentType.endsWith("xml")) {
            return BaseResult.buildError("文件格式有误!");
        }
        if (file.getSize() == 0) {
            return BaseResult.buildError("文件格为空!");
        }
        //同步数据
        FileXML fileXML = (FileXML) XMLUtil.covertXmlToObject(new FileXML(), file);
        //用户组件菜单同步，涉及菜单及按钮
        List<ResourceXML> resources = fileXML.getResources();
        List<ActionXML> actions = fileXML.getActions();
        if (CollectionUtils.isEmpty(resources)) {
            return BaseResult.buildError("导入数据为空！");
        }
        resources.forEach(item -> {
            //同步菜单
            execute(() -> {
                //保存菜单
                saveResourceXML(item);
                //保存菜单按钮
                saveResourceActionXML(item);
            });
        });
        //保存按钮
        if (!CollectionUtils.isEmpty(actions)) {
            actions.forEach(item -> execute(() -> saveActionXML(item)));
        }
        //保存item
        return BaseResult.buildSuccess("同步成功！");
    }

    private void saveResourceXML(ResourceXML item) {
        SysResource resource = sysResourceDomain.getById(item.getId());
        //同步按钮
        SysResource sysResource = new SysResource();
        BeanUtil.copyProperties(item, sysResource, "gmtCreated", "gmtModified");
        sysResource.setGmtCreated(LocalDateTime.parse(item.getGmtCreated()));
        sysResource.setGmtModified(LocalDateTime.parse(item.getGmtModified()));
        if (null == resource) {
            sysResourceDomain.insert(sysResource);
            return;
        }
        if (resource.getId().equals(item.getId())) {
            sysResourceDomain.updateById(sysResource);
            return;
        }
        throw new RuntimeException("菜单：" + item.getResourceCode() + "已存在！");
    }

    private void saveResourceActionXML(ResourceXML item) {
        List<ResourceActionXML> resourceActions = item.getResourceActions();
        if (CollectionUtils.isEmpty(resourceActions)) {
            return;
        }
        resourceActions.forEach(a -> execute(() -> {
            //保存菜按钮
            saveResourceAction(a);
        }));
    }

    private void saveResourceAction(ResourceActionXML resourceActionXML) {
        SysResourceAction resourceAction = sysResourceDomain.qryByResourceActionId(resourceActionXML.getId());
        SysResourceAction sysResourceAction = new SysResourceAction();
        BeanUtil.copyProperties(resourceActionXML, sysResourceAction, "gmtCreated", "gmtModified");
        sysResourceAction.setGmtCreated(LocalDateTime.parse(resourceActionXML.getGmtCreated()));
        sysResourceAction.setGmtModified(LocalDateTime.parse(resourceActionXML.getGmtModified()));
        if (null == resourceAction) {
            sysResourceDomain.insertResourceAction(sysResourceAction);
            return;
        }
        if (resourceAction.getId().equals(resourceActionXML.getId())) {
            sysResourceDomain.updateResourceAction(sysResourceAction);
            return;
        }
        throw new RuntimeException("菜单按钮：" + resourceActionXML.getActionCode() + "已存在！");
    }

    private void saveActionXML(ActionXML item) {
        SysAction action = sysResourceDomain.getActionById(item.getId());
        SysAction sysAction = new SysAction();
        BeanUtil.copyProperties(item, sysAction, "gmtCreated", "gmtModified");
        sysAction.setGmtCreated(LocalDateTime.parse(item.getGmtCreated()));
        sysAction.setGmtModified(LocalDateTime.parse(item.getGmtModified()));
        if (ObjectUtils.isEmpty(action)) {
            sysResourceDomain.insertAction(sysAction);
            return;
        }
        if (action.getId().equals(item.getId())) {
            sysResourceDomain.updateAction(sysAction);
            return;
        }
        throw new RuntimeException("按钮：" + item.getActionCode() + "已存在！");
    }

    private void execute(Runnable command) {
        command.run();
    }

    public BaseResult<SysResource> qryResourceRoot(String appCode) {
        return BaseResult.buildSuccess(sysResourceDomain.qryResourceRoot(appCode));
    }

    public BaseResult<List<SysResource>> getChildResourceListByParentId(SelectResourceListRequestVO param) {
        return BaseResult.buildSuccess(sysResourceDomain.getChildResourceListByParentId(param.getAppCode(), param.getParentId()));
    }

    @Transactional(rollbackFor = Exception.class)
    public BaseResult<SysResource> save(SelectResourceListRequestVO param) {
        if (ObjectUtils.isEmpty(param)) {
            return BaseResult.buildError(-1, "参数为空!");
        }
        SysResource sysResource;
        //菜单修改
        if (!ObjectUtils.isEmpty(param.getResourceId()) && param.getResourceId().compareTo(-1L) > 0) {
            sysResource = sysResourceDomain.getById(param.getResourceId());
            if (ObjectUtils.isEmpty(sysResource)) {
                return BaseResult.buildError(-1, "菜单信息不存在!");
            }
            if (!sysResource.getId().equals(param.getResourceId())) {
                return BaseResult.buildError(-1, "菜单编码不唯一!");
            }
            BeanUtil.copyProperties(param, sysResource);
            sysResourceDomain.updateById(sysResource);

        } else {
            sysResource = sysResourceDomain.qryResourceByResourceCodeAndAppCode(param.getResourceCode(), param.getAppCode());
            //菜单新增
            if (!ObjectUtils.isEmpty(sysResource)) {
                return BaseResult.buildError(-1, "菜单信息已存在!");
            } else {
                sysResource = new SysResource();
                BeanUtil.copyProperties(param, sysResource);
                sysResource.setGmtCreated(LocalDateTime.now());
                sysResourceDomain.insert(sysResource);
            }
        }
        SysResource parentResource = sysResourceDomain.getById(param.getParentId());
        if (!ObjectUtils.isEmpty(parentResource) && !parentResource.getHasChild()) {
            parentResource.setHasChild(true);
            sysResource.setGmtModified(LocalDateTime.now());
            sysResourceDomain.updateById(parentResource);
        }
        return BaseResult.buildSuccess(sysResource);
    }

}
